﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Forms;
using System.Xml.Serialization;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.VersionControl.Client;
using WpfAdvControls;

namespace TfsComLib.TfsConnection
{
    public interface ITfsConnectionData : INotifyPropertyChanged, ICloneable
    {
        /// <summary>
        ///     Tfs Server Uri
        /// </summary>
        string Uri { get; set; }

        /// <summary>
        ///     Collection Name
        /// </summary>
        string CollectionName { get; set; }

        /// <summary>
        ///     Is TFS connected now?
        /// </summary>
        [XmlIgnore]
        bool IsConnected { get; set; }

        TfsTeamProjectCollection Collection { get; set; }

        /// <summary>
        ///     Run connection window
        /// </summary>
        void Reconnect();

        /// <summary>
        ///     Check connection status with current settings
        /// </summary>
        bool TestConnect();

        VersionControlServer GetVersionControlServer();
    }

    /// <summary>
    ///     Keep data to connect to TFS. Similar to connection string for database
    /// </summary>
    [Serializable]
    public class TfsConnectionData : ITfsConnectionData
    {
        [NonSerialized]
        private readonly LibCommand changeConnection;

        [NonSerialized]
        private TfsTeamProjectCollection collection;

        private string errorMessage;


        private bool isConnected;

        private TfsConnectStatus status;

        public TfsConnectionData()
        {
            changeConnection = new LibCommand(Reconnect);
        }

        /// <summary>
        ///     Make clone - just not connected
        /// </summary>
        /// <param name="tfsConnectionData"></param>
        public TfsConnectionData(ITfsConnectionData tfsConnectionData) : this()
        {
            Uri = tfsConnectionData.Uri;
            CollectionName = tfsConnectionData.CollectionName;
        }

        [XmlIgnore]
        public TfsConnectStatus Status
        {
            get { return status; }
            set
            {
                status = value;
                if ((status & TfsConnectStatus.Connected) > 0)
                {
                    IsConnected = true;
                }
                else
                {
                    IsConnected = false;
                }
                ErrorMessage = status.ToString();
                NotifyPropertyChange("Status");
            }
        }

        /// <summary>
        ///     If error while connect
        /// </summary>
        [XmlIgnore]
        public string ErrorMessage
        {
            get { return errorMessage; }
            set
            {
                errorMessage = value;
                NotifyPropertyChange("ErrorMessage");
            }
        }

        [XmlIgnore]
        public LibCommand ChangeConnection
        {
            get { return changeConnection; }
        }

        /// <summary>
        ///     Version Control Server dependency property
        /// </summary>
        [XmlIgnore]
        public VersionControlServer VersionControlServer
        {
            get { return GetVersionControlServer(); }
            set { }
        }

        /// <summary>
        ///     Tfs Server Uri
        /// </summary>
        public string Uri { get; set; }

        /// <summary>
        ///     Collection Name
        /// </summary>
        public string CollectionName { get; set; }

        /// <summary>
        ///     Is TFS connected now?
        /// </summary>
        [XmlIgnore]
        public bool IsConnected
        {
            get { return isConnected; }
            set
            {
                isConnected = value;
                NotifyPropertyChange("IsConnected");
            }
        }

        /// <summary>
        ///     Tfs Collection
        /// </summary>
        [XmlIgnore]
        public TfsTeamProjectCollection Collection
        {
            get { return collection; }
            set { collection = value; }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        /// <summary>
        ///     Run connection window
        /// </summary>
        public void Reconnect()
        {
            using (var teamProjectPicker = new TeamProjectPicker(TeamProjectPickerMode.NoProject, false))
            {
                if (collection != null)
                {
                    teamProjectPicker.SelectedTeamProjectCollection = collection;
                }
                var dialogResult = teamProjectPicker.ShowDialog();
                if (dialogResult == DialogResult.OK)
                {
                    collection = teamProjectPicker.SelectedTeamProjectCollection;
                    Uri = collection.ConfigurationServer.Uri.AbsoluteUri;
                    CollectionName = collection.CatalogNode.Resource.DisplayName;
                    Status = TfsConnectStatus.Connected;
                    NotifyPropertyChange("Uri");
                    NotifyPropertyChange("CollectionName");
                    NotifyPropertyChange("VersionControlServer");
                    NotifyPropertyChange("Collection");
                }
            }
        }


        /// <summary>
        ///     Check connection status with current settings
        /// </summary>
        /// <returns>True if connected</returns>
        public bool TestConnect()
        {
            var isConnected = false;
            Status = TfsConnectStatus.Disconnected;
            try
            {
                var tfsConfigurationServer =
                    TfsConfigurationServerFactory.GetConfigurationServer(new Uri(Uri));
                if (tfsConfigurationServer == null)
                {
                    return false;
                }
                // Get the catalog of team project collections
                var catalogNode = tfsConfigurationServer.CatalogNode;
                var tpcNodes = catalogNode.QueryChildren(
                    new[] {CatalogResourceTypes.ProjectCollection},
                    false, CatalogQueryOptions.None);

                // List the team project collections
                foreach (var tpcNode in tpcNodes)
                {
                    if (tpcNode.Resource.DisplayName.ToLower() == CollectionName.ToLower())
                    {
                        // Use the InstanceId property to get the team project collection
                        var tpcId = new Guid(tpcNode.Resource.Properties["InstanceId"]);
                        collection = tfsConfigurationServer.GetTeamProjectCollection(tpcId);
                        if (collection != null)
                        {
                            isConnected = true;
                        }
                    }
                }
                if (isConnected)
                {
                    Status = TfsConnectStatus.Connected;
                }
                else
                {
                    Status = TfsConnectStatus.Disconnected;
                }
            }
            catch (Exception ex)
            {
                Status = TfsConnectStatus.ConnectError;
                ErrorMessage = ex.Message;
                // failed to connect
            }
            return isConnected;
        }

        public VersionControlServer GetVersionControlServer()
        {
            if (collection != null)
            {
                return collection.GetService<VersionControlServer>();
            }
            return null;
        }

        public object Clone()
        {
            return new TfsConnectionData(this);
        }

        /// <summary>
        ///     Уведомляет слушателей об изменении свойства
        /// </summary>
        /// <param name="prop"></param>
        private void NotifyPropertyChange(string prop)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(prop));
            }
        }


        public void SetVersionControlServer(VersionControlServer versionControlServer)
        {
            Collection = versionControlServer.TeamProjectCollection;
            CollectionName = Collection.Name;
            Uri = versionControlServer.TeamProjectCollection.ConfigurationServer.Uri.AbsoluteUri;
            NotifyPropertyChange("Uri");
            NotifyPropertyChange("CollectionName");
            NotifyPropertyChange("VersionControlServer");
            NotifyPropertyChange("Collection");
        }
    }
}